#ifndef TRIGGER_H
#define TRIGGER_H
//-----------------------------------------------------------------------------
//
//  Name:   Trigger.h
//
//  Author: Mat Buckland (www.ai-junkie.com)
//
//  Desc:   base class for a trigger. A trigger is an object that is
//          activated when an entity moves within its region of influence.
//
//-----------------------------------------------------------------------------
#include "game/BaseGameEntity.h"
#include "TriggerRegion.h"

struct Telegram;
struct Vector2D;

template < class entity_type >
class Trigger : public BaseGameEntity
{
  private:

    //Every trigger owns a trigger region. If an entity comes within this 
    //region the trigger is activated
    TriggerRegion* m_pRegionOfInfluence;

    //if this is true the trigger will be removed from the game
    bool m_bRemoveFromGame;

    //it's convenient to be able to deactivate certain types of triggers
    //on an event. Therefore a trigger can only be triggered when this
    //value is true (respawning triggers make good use of this facility)
    bool m_bActive;

    //some types of trigger are twinned with a graph node. This enables
    //the pathfinding component of an AI to search a navgraph for a specific
    //type of trigger.
    int m_iGraphNodeIndex;

  protected:

    void SetGraphNodeIndex( int idx )
    {
      m_iGraphNodeIndex = idx;
    }

    void SetToBeRemovedFromGame()
    {
      m_bRemoveFromGame = true;
    }
    void SetInactive()
    {
      m_bActive = false;
    }
    void SetActive()
    {
      m_bActive = true;
    }

    //returns true if the entity given by a position and bounding radius is
    //overlapping the trigger region
    bool isTouchingTrigger( Vector2D EntityPos,
                            double EntityRadius ) const;

    //child classes use one of these methods to initialize the trigger region
    void AddCircularTriggerRegion( Vector2D center,
                                   double radius );
    void AddRectangularTriggerRegion( Vector2D TopLeft,
                                      Vector2D BottomRight );

  public:

    Trigger( unsigned int id )
        : BaseGameEntity( id ),
          m_bRemoveFromGame( false ),
          m_bActive( true ),
          m_iGraphNodeIndex( -1 ),
          m_pRegionOfInfluence( NULL )

    {
    }

    virtual ~Trigger()
    {
      delete m_pRegionOfInfluence;
    }

    //when this is called the trigger determines if the entity is within the
    //trigger's region of influence. If it is then the trigger will be 
    //triggered and the appropriate action will be taken.
    virtual void Try( entity_type* ) = 0;

    //called each update-step of the game. This methods updates any internal
    //state the trigger may have
    virtual void Update() = 0;

    int GraphNodeIndex() const
    {
      return m_iGraphNodeIndex;
    }
    bool isToBeRemoved() const
    {
      return m_bRemoveFromGame;
    }
    bool isActive()
    {
      return m_bActive;
    }
};

//------------------------ AddCircularTriggerRegion ---------------------------
//-----------------------------------------------------------------------------
template < class entity_type >
void Trigger < entity_type >::AddCircularTriggerRegion( Vector2D center,
                                                        double radius )
{
  //if this replaces an existing region, tidy up memory
  if ( m_pRegionOfInfluence ) delete m_pRegionOfInfluence;

  m_pRegionOfInfluence = new TriggerRegion_Circle( center,
                                                   radius );
}

//--------------------- AddRectangularTriggerRegion ---------------------------
//-----------------------------------------------------------------------------
template < class entity_type >
void Trigger < entity_type >::AddRectangularTriggerRegion( Vector2D TopLeft,
                                                           Vector2D BottomRight )
{
  //if this replaces an existing region, tidy up memory
  if ( m_pRegionOfInfluence ) delete m_pRegionOfInfluence;

  m_pRegionOfInfluence = new TriggerRegion_Rectangle( TopLeft,
                                                      BottomRight );
}

//--------------------- isTouchingTrigger -------------------------------------
//-----------------------------------------------------------------------------
template < class entity_type >
bool Trigger < entity_type >::isTouchingTrigger( Vector2D EntityPos,
                                                 double EntityRadius ) const
{
  if ( m_pRegionOfInfluence ) {
    return m_pRegionOfInfluence->isTouching( EntityPos,
                                             EntityRadius );
  }

  return false;
}

#endif
